Skip to content

feat(parser): add Reasonix session support - #733

Merged
wesm merged 2 commits into
kenn-io:mainfrom
rodboev:pr/reasonix-parser
Jun 19, 2026
Merged

feat(parser): add Reasonix session support#733
wesm merged 2 commits into
kenn-io:mainfrom
rodboev:pr/reasonix-parser

Conversation

@rodboev

@rodboev rodboev commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add first-class Reasonix session discovery and parsing so Reasonix activity syncs into agentsview.
  • Wire Reasonix through the sync engine's file-based parser switch, the watcher's path classifier, and the registry completeness tests so discovery reaches import on both initial sync and live file changes.

Scope

  • New parser coverage is limited to the Reasonix JSONL transcript + .jsonl.meta sidecar described in Feature Request: Add Reasonix agent parser support #720, across all four documented layouts: project sessions, global sessions, global subagents, and archive sessions.
  • Project association is preserved from discovery through to the parsed session, and metadata timestamps from .jsonl.meta sidecars are kept when present rather than overwritten during parsing.
  • No pricing, PostgreSQL-only behavior, or desktop-specific UI changes are part of this slice.

Review Notes

  • internal/parser/reasonix.go covers the path layout, transcript-field mapping, and metadata sidecar fallback.
  • internal/sync/engine.go has two additions: processReasonix for the file processor switch, and a Reasonix branch in classifyOnePath for watcher-triggered syncs.
  • internal/parser/types_test.go and internal/parser/reasonix_test.go cover registry guardrails, timestamp preservation, and space-containing session IDs.
  • Validation ran locally with CGO_ENABLED=1 go test -tags "fts5,kit_posthog_disabled" ./internal/parser/... ./internal/sync/... -run "Reasonix|Registry" -count=1; broader CI covers the rest of the Go matrix.

Fixes #720

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (df481fb)

Summary verdict: Medium issues remain around Reasonix metadata synchronization and deterministic timestamps.

Medium

  • Location: internal/sync/engine.go:3987
    Problem: Reasonix parses .jsonl.meta for model and timestamps, but sync skip/change detection only uses the transcript file. Metadata-only updates, or metadata created after the transcript event, can be ignored because *.jsonl.meta is not classified back to the transcript and shouldSkipByPath compares only the JSONL size/mtime.
    Fix: Add a Reasonix effective file info helper like commandCodeEffectiveInfo, map .jsonl.meta events to the owning .jsonl in classifyOnePath, and use combined mtime/size for skip checks, discoveredFileMtime, and stored sess.File metadata.

  • Location: internal/parser/reasonix.go:120
    Problem: Sessions without valid metadata timestamps use time.Now() while parsing, so archived or no-meta Reasonix sessions appear as if they occurred at sync time, and their timestamps change on force reparse or data-version resync.
    Fix: Use a deterministic fallback such as the timestamp embedded in the Reasonix filename/session ID, falling back to file mtime if needed, and set it once rather than calling time.Now() per message.


Panel: ci_default_security | Synthesis: codex, 9s | Members: codex_default (codex/default, done, 4m0s), codex_security (codex/security, done, 2m17s) | Total: 6m26s

@rodboev
rodboev force-pushed the pr/reasonix-parser branch from df481fb to 0e4c133 Compare June 19, 2026 00:19
@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (f051165)

Summary verdict: one Medium issue remains; no Critical or High findings were reported.

Medium

  • Location: internal/sync/engine.go:4736
  • Problem: Reasonix .jsonl.meta changes are ignored by live classification, and full sync skips unchanged transcripts using only the .jsonl mtime at processReasonix. Since the parser reads model/timestamps from the sidecar, metadata written or updated after the transcript can remain permanently stale.
  • Fix: Map *.jsonl.meta events back to the sibling .jsonl and use an effective mtime/fingerprint that includes the sidecar when deciding whether to skip.

Panel: ci_default_security | Synthesis: codex, 6s | Members: codex_default (codex/default, done, 3m11s), codex_security (codex/security, done, 2m16s) | Total: 5m33s

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (9d10ac5)

Medium issues remain: Reasonix metadata updates can be missed during incremental sync, and missing metadata timestamps can make archived sessions look newly active.

Medium

  • internal/sync/engine.go:2877 and internal/sync/engine.go:8012
    Reasonix .jsonl.meta mtime is only used inside processReasonix; SyncAllSince still filters by transcript mtime via discoveredFileMtime, and SourceMtime falls through to statting only the .jsonl. A metadata-only update can be dropped before parsing, so periodic/incremental sync and watcher fallback miss it.
    Fix: Add Reasonix branches in discoveredFileMtime and SourceMtime that use reasonixEffectiveInfo, with a regression test like the existing Vibe/Command Code sidecar tests.

  • internal/parser/reasonix.go:120
    Sessions without complete metadata get StartedAt/EndedAt from time.Now() during parsing. Archive sessions are explicitly supported without .meta, so old sessions will appear as newly active whenever parsed; if only updated_at is valid, it is overwritten because hasMetaTimes is false unless both timestamps parsed.
    Fix: Track metadata start/end independently and fill only missing timestamps from a stable source such as the filename timestamp or file mtime after parsing.


Panel: ci_default_security | Synthesis: codex, 9s | Members: codex_default (codex/default, done, 4m6s), codex_security (codex/security, done, 2m42s) | Total: 6m57s

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (ff6570a)

Summary verdict: one medium issue remains; no high or critical findings were reported.

Medium

  • internal/sync/engine.go:7077 - Reasonix sidecar metadata can populate per-message Model, and the sync path re-parses when .jsonl.meta changes, but Reasonix is not forced through the full message replace path. If metadata is added or its model changes without new transcript ordinals, writeMessages inserts nothing and existing messages keep stale or empty model values.
    • Fix: Include parser.AgentReasonix in shouldReplaceFullParseMessages, or otherwise update existing message metadata during Reasonix re-parses. Add a sync test for a metadata-only model update.

Panel: ci_default_security | Synthesis: codex, 6s | Members: codex_default (codex/default, done, 5m30s), codex_security (codex/security, done, 2m45s) | Total: 8m21s

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (cb5ca9d)

Summary verdict: changes need follow-up before merge due to two medium correctness gaps in Reasonix timestamp handling and session discovery.

Medium

  • internal/parser/reasonix.go:167
    Partial metadata timestamps are still applied individually. If only created_at or only updated_at parses, the other timestamp falls back to transcript mtime, which can produce incorrect ranges such as StartedAt > EndedAt; hasMetaTimes is computed but never used.
    Fix: Parse metadata timestamps into locals and assign them only when both are valid. Otherwise, fall back both timestamps consistently to file mtime. Add tests for missing or malformed created_at and updated_at.

  • internal/parser/reasonix.go:307
    Project-session discovery ignores bare projects/{project}/sessions/*.jsonl files even though that layout is documented. The watcher classifier and FindReasonixSourceFile also only handle projects/{project}/sessions/{id}/{id}.jsonl, so bare project sessions would never sync or resolve.
    Fix: Add bare project .jsonl handling to DiscoverReasonixSessions, classifyReasonixPath, and FindReasonixSourceFile, with matching tests.


Panel: ci_default_security | Synthesis: codex, 13s | Members: codex_default (codex/default, done, 4m49s), codex_security (codex/security, done, 1m48s) | Total: 6m50s

@rodboev

rodboev commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the last Reasonix follow-up in 2163ced2.

  1. internal/parser/reasonix.go now only applies metadata timestamps when both created_at and updated_at parse, otherwise both values fall back together to the transcript mtime.
  2. Bare project sessions under projects/{project}/sessions/{id}.jsonl now discover, classify, and resolve the same way as the nested project layout, including .jsonl.meta watcher events.
  3. Added focused parser and sync coverage for the partial-metadata and bare-project-session cases.

Local verification:

  • CGO_ENABLED=1 go test -tags "fts5,kit_posthog_disabled" ./internal/parser/... ./internal/sync/... -run "Reasonix|ClassifyOnePathReasonixProjectBareMeta" -count=1
  • go vet ./internal/parser/... ./internal/sync/...

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (2163ced)

Medium confidence with one Medium finding: Reasonix metadata updates are synced but not reflected in visible session fields.

Medium

  • internal/parser/reasonix.go:160
    The Reasonix sidecar parser reads id, workspace_root, and topic_title, but only applies model and timestamps to the parsed session. Metadata-only updates to the title or workspace now trigger a sync, but the visible session name, cwd, and project remain unset, so global Reasonix sessions are poorly grouped and sidecar title changes have no user-visible effect.
    Fix: Populate ParsedSession.SessionName, Cwd, and derived Project from the metadata, preserving the discovered project for project-scoped paths; add a metadata-only sync test for those fields.

Panel: ci_default_security | Synthesis: codex, 6s | Members: codex_default (codex/default, done, 6m1s), codex_security (codex/security, done, 2m9s) | Total: 8m16s

@rodboev

rodboev commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Handled the new Reasonix metadata follow-up in e375b580.

  1. internal/parser/reasonix.go now projects topic_title into SessionName, workspace_root into Cwd, and derives Project from that cwd for global Reasonix sessions.
  2. Project-scoped Reasonix paths still keep the discovered project in processReasonix, so metadata only fills the missing global-session fields.
  3. Added parser coverage for the metadata field mapping, plus a sync regression that updates only .jsonl.meta and verifies the stored display name, session name, cwd, and project all refresh.

Local verification:

  • CGO_ENABLED=1 go test -tags "fts5,kit_posthog_disabled" ./internal/parser/... ./internal/sync/... -run "Reasonix|ClassifyOnePathReasonixProjectBareMeta|SyncPathsReasonixMetadataOnlySessionFieldUpdate" -count=1
  • go vet ./internal/parser/... ./internal/sync/...

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (e375b58)

Medium issue found: Reasonix project-layout sync can overwrite parser-derived project metadata.

Medium

  • internal/sync/engine.go:4831 - Project-layout Reasonix syncs always overwrite the parser-derived project from .jsonl.meta workspace_root with the directory name from discovery. Sidecar workspace_root updates therefore do not update the stored project for those sessions.
    • Suggested fix: use the discovered project only as a fallback, such as assigning file.Project only when sess.Project is empty, and add a project-layout metadata update test.

Panel: ci_default_security | Synthesis: codex, 7s | Members: codex_default (codex/default, done, 5m29s), codex_security (codex/security, done, 1m29s) | Total: 7m5s

@rodboev

rodboev commented Jun 19, 2026

Copy link
Copy Markdown
Contributor Author

Handled the project-layout follow-up in 90e334ac.

  1. internal/sync/engine.go now uses the discovered Reasonix project only as a fallback, so metadata-derived project updates from workspace_root are preserved instead of being overwritten for project-layout sessions.
  2. Added a project-layout sync regression that updates only .jsonl.meta and verifies the stored project changes from the metadata value on reparse.

Local verification:

  • CGO_ENABLED=1 go test -tags "fts5,kit_posthog_disabled" ./internal/parser/... ./internal/sync/... -run "Reasonix|ClassifyOnePathReasonixProjectBareMeta|SyncPathsReasonixMetadataOnlySessionFieldUpdate|SyncPathsReasonixProjectLayoutMetadataProjectUpdate" -count=1
  • go vet ./internal/parser/... ./internal/sync/...

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (90e334a)

Clean for Medium+ severity: no reportable findings.

Low-severity issue from one review was omitted per instructions.


Panel: ci_default_security | Synthesis: codex, 4s | Members: codex_default (codex/default, done, 8m37s), codex_security (codex/security, done, 1m20s) | Total: 10m1s

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (0ce1a5d)

Medium severity issue found; no Critical or High findings.

Medium

  • internal/sync/engine.go:8171 - SyncSingleSession has no Reasonix case to populate file.Project. processReasonix only uses file.Project when metadata has no workspace_root, so a single-session resync of projects/<project>/sessions/... without workspace metadata overwrites the stored project with empty, unlike SyncAll/SyncPaths.

    Suggested fix: Add a Reasonix branch that derives the project from the configured Reasonix root/path using the same semantics as classifyReasonixPath or discovery, and cover it with a single-session resync test.


Panel: ci_default_security | Synthesis: codex, 7s | Members: codex_default (codex/default, done, 5m12s), codex_security (codex/security, done, 1m53s) | Total: 7m12s

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (b50f12b)

Summary verdict: one Medium correctness issue remains; no High or Critical findings were reported.

Medium

  • internal/parser/reasonix.go:321 - Malformed or partially written .jsonl.meta files are treated the same as missing metadata. A watcher event during a partial sidecar write can reparse the transcript with empty SessionName, Cwd, and metadata-derived Project, and the session upsert will overwrite previously correct values.

    Suggested fix: Distinguish missing sidecars from read/JSON parse errors. Return a parse error or preserve existing metadata on malformed sidecars, and add a regression test for metadata parse failure after an initial successful sync.


Panel: ci_default_security | Synthesis: codex, 7s | Members: codex_default (codex/default, done, 6m18s), codex_security (codex/security, done, 2m51s) | Total: 9m16s

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (82ba227)

Medium issue found: Reasonix sidecar-only fixes can be skipped due to stale transcript mtime caching.

Medium

  • Location: internal/sync/engine.go:3652
  • Problem: Reasonix still uses the transcript file's mtime for the generic skip cache. If a malformed .jsonl.meta causes a parse error, that transcript mtime is cached; when the sidecar is later fixed without changing the transcript, processFile skips before processReasonix can see the updated sidecar mtime.
  • Fix: Mirror the Vibe handling and set mtime = reasonixEffectiveInfo(file.Path, info).ModTime().UnixNano() before the skip-cache check, or avoid skip-caching Reasonix metadata parse errors. Add a test that malformed metadata is retried after a sidecar-only fix.

Panel: ci_default_security | Synthesis: codex, 8s | Members: codex_default (codex/default, done, 3m8s), codex_security (codex/security, done, 1m49s) | Total: 5m5s

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (71ebbbb)

Summary verdict: One medium correctness issue needs attention; no security findings were reported.

Medium

  • internal/sync/engine.go:8297 - Reasonix single-session resync can preserve a stale DB project for global/archive sessions when metadata is removed or no longer contains workspace_root. Bulk/watch sync clears the project because file.Project stays empty, but SyncSingleSessionContext falls back to the existing DB project, and processReasonix writes it back when the parser has no metadata-derived project.

    Suggested fix: Only fall back to the stored DB project when path classification fails entirely, not when Reasonix classification succeeds with an empty project for global/archive layouts.


Panel: ci_default_security | Synthesis: codex, 6s | Members: codex_default (codex/default, done, 5m6s), codex_security (codex/security, done, 2m32s) | Total: 7m44s

@roborev-ci

roborev-ci Bot commented Jun 19, 2026

Copy link
Copy Markdown

roborev: Combined Review (78f7311)

No issues found.


Panel: ci_default_security | Synthesis: codex | Members: codex_default (codex/default, done, 7m22s), codex_security (codex/security, done, 3m6s) | Total: 10m28s

- fix(parser): address review findings for Reasonix parser (kenn-io#720)
- fix(parser): watch projects subdir and guard partial metadata timestamps (kenn-io#720)
- Use CutSuffix instead of HasSuffix+TrimSuffix
- Extract Reasonix classification to stay within nilaway CFG limit
- Include sidecar mtime in skip decisions for metadata-only updates
- Use sidecar mtime in all sync paths, fall back to file mtime for timestamps
- Force full message replace on Reasonix re-parse for metadata-only changes
- fix(parser): keep Reasonix metadata and project sessions consistent
- fix(parser): surface Reasonix sidecar metadata in session fields
- fix(sync): preserve Reasonix workspace-derived project updates
- docs: add Reasonix to supported agents
- fix: preserve Reasonix project on single sync
- fix: parse Reasonix tool results
- fix: reject malformed Reasonix metadata
- fix: retry Reasonix sync after metadata recovery
- fix: handle deleted Reasonix metadata sidecars
- fix: ignore deleted Reasonix transcripts
- fix: clear Reasonix project on single resync

Co-Authored-By: Wes McKinney <wesmckinn+git@gmail.com>
@wesm
wesm force-pushed the pr/reasonix-parser branch from 78f7311 to ac632f4 Compare June 19, 2026 17:06
Rebasing the Reasonix parser onto main combined main's inline Aider
classification with the new Reasonix paths in classifyOnePath, pushing
the function to 502 CFG blocks (nilaway's limit is 500). Move the Aider
block into a classifyAiderPath helper, mirroring classifyReasonixPath
and classifyVisualStudioCopilotPath. Behavior is unchanged.
@wesm
wesm merged commit a1ba873 into kenn-io:main Jun 19, 2026
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Add Reasonix agent parser support

2 participants